﻿using Base.Api.Repository;
using Base.Data.Entity;
using Castle.Core.Internal;
using Common.AspNetCore;
using Common.EF;
using Common.Infrastructure;
using Common.Infrastructure.Structs;
using Common.Infrastructure.Utils;
using Common.Models.Base;
using Common.RunModels.Base;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;

namespace Base.Api.Service
{
    public class BaseLabelService : CommonService
    {
        private readonly IConfiguration config;
        private readonly string lang;
        private readonly BaseRepository baseRepository;
        private readonly ILogger<BaseLabelService> logger;

        public BaseLabelService(IServiceProvider provider, IConfiguration c, BaseRepository baseRep, ILogger<BaseLabelService> logger) : base(provider)
        {
            this.config = c;
            this.lang = !string.IsNullOrEmpty(this.config["DefaultLang"]) ? this.config["DefaultLang"] : "CN";
            this.baseRepository = baseRep;
            this.logger = logger;
        }

        public async Task<LibMessageApiResultModel> GetLibMessageByApiStartAsync(LibMessageApiParamModel model)
        {
            if (string.IsNullOrEmpty(model.ApiKey))
            {
                return null;
            }

            var type = model.Type == 0 ? 2 : 6;
            List<t_base_label> addBaseLabels = new List<t_base_label>();
            List<t_base_label> updateBaseLabels = new List<t_base_label>();
            List<t_base_label_detail> addBaseLabelDetails = new List<t_base_label_detail>();
            List<t_base_label_detail> updateBaseLabelDetails = new List<t_base_label_detail>();
            var codes = model.Messages.Select(t => t.Code).Distinct().ToList();

            (List<t_base_label> baseLabels, List<t_base_label_detail> baseLabelDetails) = await GetBaseLabelByCodeAsync(type, model.ApiKey, codes);

            foreach (var s in model.Messages)
            {
                t_base_label baseLabel = baseLabels?.FirstOrDefault(t => t.label_key == s.Code);
                if (baseLabel == null)
                {
                    baseLabel = new t_base_label() { type = type, api_key = model.ApiKey, label_key = s.Code };
                    this.SetEntityId(baseLabel);
                    addBaseLabels.Add(baseLabel);
                    baseLabels.Add(baseLabel);
                }

                s.Details.ForEach(item =>
                {
                    if (string.IsNullOrEmpty(item.Lang))
                    {
                        item.Lang = this.lang;
                    }

                    var detail = baseLabelDetails?.FirstOrDefault(t => t.base_label_id == baseLabel.id && t.lang == item.Lang);
                    if (detail == null)
                    {
                        detail = new t_base_label_detail() { base_label_id = baseLabel.id, lang = item.Lang };
                        this.SetEntityId(detail, detail.base_label_id);
                        addBaseLabelDetails.Add(detail);
                        baseLabelDetails.Add(detail);
                    }
                    else
                    {
                        if (detail.is_edit_by_menu || detail.label == item.Format)
                        {
                            return;
                        }

                        updateBaseLabelDetails.Add(detail);
                    }

                    detail.label = item.Format;
                });
            }

            await this.baseRepository.CommitChangesByCommonAsync(() =>
            {
                this.baseRepository.CommonRepository.AddEntities(addBaseLabels);
                this.baseRepository.CommonRepository.AddEntities(addBaseLabelDetails);
                this.baseRepository.CommonRepository.UpdateEntities(updateBaseLabels);
                this.baseRepository.CommonRepository.UpdateEntities(updateBaseLabelDetails);
            });

            return GetLibMessageApiResultModel(baseLabels, baseLabelDetails);
        }

        public async Task<LibMessageApiResultModel> GetLibMessageBySyncDataAsync(LibMessageApiParamModel model)
        {
            if (string.IsNullOrEmpty(model.ApiKey))
            {
                return null;
            }

            var codes = model.Messages.Select(t => t.Code).Distinct().ToList();

            (List<t_base_label> baseLabels, List<t_base_label_detail> baseLabelDetails) = await GetBaseLabelByCodeAsync(2, model.ApiKey, codes);

            return GetLibMessageApiResultModel(baseLabels, baseLabelDetails);
        }

        public async Task<VueI18nMessageResultModel> GetVueI18nMessageAsync(VueI18nMessageParamModel model)
        {
            if (string.IsNullOrEmpty(model.ApiKey))
            {
                return null;
            }

            var templang = model.Lang;
            var baseLabels = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label>(null, t => t.type == model.Type && t.api_key == model.ApiKey);
            var baseLabelIds = baseLabels.Select(t => t.id).ToList();
            var baseLabelDetails = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label_detail>(null, t => baseLabelIds.Contains(t.base_label_id));
            ////var enbaseLabelDetails = await LangChangeAsync(baseLabelDetails, "en");
            ////var thbaseLabelDetails = await LangChangeAsync(baseLabelDetails, "th");
            ////if (enbaseLabelDetails != null)
            ////{
            ////    baseLabelDetails.AddRange(enbaseLabelDetails);
            ////}

            ////if (thbaseLabelDetails != null)
            ////{
            ////    baseLabelDetails.AddRange(thbaseLabelDetails);
            ////}

            VueI18nMessageResultModel result = new VueI18nMessageResultModel();
            baseLabels.ForEach(t3 =>
            {
                var msg = new VueI18nMessageDetailResultModel() { Key = t3.label_key };
                result.Details.Add(msg);
                t_base_label_detail r = null;
                var details = baseLabelDetails.Where(t2 => t2.base_label_id == t3.id);

                if (string.IsNullOrEmpty(templang))
                {
                    r = details.FirstOrDefault(t => string.IsNullOrEmpty(t.lang));
                    if (r == null)
                    {
                        r = details.OrderBy(t => t.lang).FirstOrDefault();
                    }
                }
                else
                {
                    r = details.FirstOrDefault(t => string.Compare(t.lang, templang, true) == 0);
                    if (r == null)
                    {
                        r = details.OrderBy(t => t.lang).FirstOrDefault();
                    }
                }

                if (r == null)
                {
                    r = details.FirstOrDefault();
                }

                if (r != null)
                {
                    msg.Label = r.label;
                }
            });

            return result;
        }

        public async Task<List<m_base_label>> GetBaseLabelsByIdsAsync(ModelIdRequest model)
        {
            var result = await this.baseRepository.CommonModelRepository.GetModelsAsync<m_base_label>(model.Ids);
            await FillLangDataByBaseLabelAsync(result);
            return result;
        }

        public async Task<bool> SaveBaseLabelAsync(ModelSaveRequest request)
        {
            List<t_base_label> addBaseLabels = new List<t_base_label>();
            List<t_base_label> updateBaseLabels = new List<t_base_label>();
            List<t_base_label_detail> addBaseLabelDetails = new List<t_base_label_detail>();
            List<t_base_label_detail> updateBaseLabelDetails = new List<t_base_label_detail>();
            var processR = request.Details.FirstOrDefault(t => t.ModelName == "t_base_label" || t.ModelName == "m_base_label");

            if (processR == null || string.IsNullOrEmpty(processR.ModelData))
            {
                return true;
            }

            var list = processR.ModelData.ToObjectFromJson<List<m_base_label>>();
            var ids = list.Select(t => t.id).Distinct().ToList();

            var baseLabels = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label>(ids);
            var baseLabelIds = baseLabels.Select(t => t.id).ToList();
            var baseLabelDetails = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label_detail>(null, t => baseLabelIds.Contains(t.base_label_id));

            list = await LangChangeAsync(list);

            foreach (var s in list)
            {
                var b = baseLabels.FirstOrDefault(t => t.id == s.id);
                if (b != null && b.remark != s.remark)
                {
                    b.remark = s.remark;
                    updateBaseLabels.Add(b);
                }

                DoAddLabelDetail(b, baseLabelDetails, addBaseLabelDetails, updateBaseLabelDetails, s.label_label_cn, "CN");
                DoAddLabelDetail(b, baseLabelDetails, addBaseLabelDetails, updateBaseLabelDetails, s.label_label_en, "EN");
                DoAddLabelDetail(b, baseLabelDetails, addBaseLabelDetails, updateBaseLabelDetails, s.label_label_th, "TH");
            }

            await this.baseRepository.CommitChangesByCommonAsync(() =>
            {
                this.baseRepository.CommonRepository.AddEntities(addBaseLabels);
                this.baseRepository.CommonRepository.AddEntities(addBaseLabelDetails);
                this.baseRepository.CommonRepository.UpdateEntities(updateBaseLabels);
                this.baseRepository.CommonRepository.UpdateEntities(updateBaseLabelDetails);
            });

            return !this.HasThrow;
        }

        public async Task<ApiPagedResult<m_base_label>> GetBaseLabelOrderPageAsync(ModelOrderPageRequest model)
        {
            var boxkey = model.OrderPageParam.Params.FirstOrDefault(t => t.Key == "detail_key")?.Value;
            var apiKey = model.OrderPageParam.Params.FirstOrDefault(t => t.Key == "api_key")?.Value;
            if (!string.IsNullOrEmpty(boxkey))
            {
                var details = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label_detail>(null, t => t.label.Contains(boxkey));
                if (!details.Any())
                {
                    return new ApiPagedResult<m_base_label>();
                }

                model.OrderPageParam.Group.Rules.Add(new ApiRuleParam() { Field = "id", Value = string.Join(",", details.Select(t => t.base_label_id).Distinct()), Operate = ApiRuleOperateEnum.InByString });
            }

            var orgId = model.OrderPageParam.OrgId;
            model.OrderPageParam.OrgId = null;
            ApiGroupParam g = new ApiGroupParam() { IsAnd = false };
            g.Rules.Add(new ApiRuleParam() { Field = "type", Value = "1", Operate = ApiRuleOperateEnum.不等于 });
            g.Rules.Add(new ApiRuleParam() { Field = "org_id", Value = orgId, Operate = ApiRuleOperateEnum.等于 });
            model.OrderPageParam.Group.Groups.Add(g);

            model.OrderPageParam.Group.Rules.Add(new ApiRuleParam() { Field = "api_key", Value = apiKey });

            var result = await this.baseRepository.CommonModelRepository.GetOrderPageModelsAsync<m_base_label>(model.OrderPageParam);
            if (result.Data.Any())
            {
                await FillLangDataByBaseLabelAsync(result.Data);
            }

            return result;
        }

        public async Task<bool> SaveVueI8MessageAsync(SaveVueI18nMessageParamModel model)
        {
            if (string.IsNullOrEmpty(model.ApiKey))
            {
                return false;
            }

            List<t_base_label> addBaseLabels = new List<t_base_label>();
            List<t_base_label> updateBaseLabels = new List<t_base_label>();
            List<t_base_label_detail> addBaseLabelDetails = new List<t_base_label_detail>();
            List<t_base_label_detail> updateBaseLabelDetails = new List<t_base_label_detail>();

            var codes = model.Details.Select(t => t.Key).Distinct().ToList();

            var baseLabels = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label>(null, t => t.type == model.Type && t.api_key == model.ApiKey && codes.Contains(t.label_key));
            var baseLabelIds = baseLabels.Select(t => t.id).ToList();
            var baseLabelDetails = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label_detail>(null, t => baseLabelIds.Contains(t.base_label_id));
            foreach (var s in model.Details)
            {
                t_base_label baseLabel = baseLabels?.FirstOrDefault(t => t.label_key == s.Key);
                if (baseLabel == null)
                {
                    baseLabel = new t_base_label() { type = model.Type, api_key = model.ApiKey, label_key = s.Key };
                    this.SetEntityId(baseLabel);
                    addBaseLabels.Add(baseLabel);
                    baseLabels.Add(baseLabel);
                }

                var detail = baseLabelDetails?.FirstOrDefault(t => t.base_label_id == baseLabel.id && t.lang == this.lang);
                if (detail == null)
                {
                    detail = new t_base_label_detail() { base_label_id = baseLabel.id, lang = this.lang };
                    this.SetEntityId(detail, detail.base_label_id);
                    addBaseLabelDetails.Add(detail);
                    baseLabelDetails.Add(detail);
                }
                else
                {
                    if (detail.is_edit_by_menu || detail.label == s.Label)
                    {
                        continue;
                    }

                    updateBaseLabelDetails.Add(detail);
                }

                detail.label = s.Label;
            }

            await this.baseRepository.CommitChangesByCommonAsync(() =>
            {
                this.baseRepository.CommonRepository.AddEntities(addBaseLabels);
                this.baseRepository.CommonRepository.AddEntities(addBaseLabelDetails);
                this.baseRepository.CommonRepository.UpdateEntities(updateBaseLabels);
                this.baseRepository.CommonRepository.UpdateEntities(updateBaseLabelDetails);
            });

            return !this.HasThrow;
        }

        public async Task<SystemTranslateResultModel> SystemTranslateAsync(SystemTranslateParamModel model)
        {
            if (model == null || model.SrcValues == null || !model.SrcValues.Any())
            {
                return new SystemTranslateResultModel();
            }

            if (model.Langs == null || !model.Langs.Any())
            {
                model.Langs = new List<string>();
                model.Langs.Add("EN");
            }

            SystemTranslateResultModel ret = new SystemTranslateResultModel();
            foreach (var lang in model.Langs)
            {
                var p = await DoSystemTranslateAsync(model.SrcValues, model.SrcLang, lang, ret);
                if (p != null)
                {
                    ret.Details.AddRange(p);
                }
            }

            return ret;
        }

        private async Task<List<SystemTranslateDetailResultModel>> DoSystemTranslateAsync(List<string> values, string srcLang, string lang, SystemTranslateResultModel ret)
        {
            if (values == null || !values.Any())
            {
                return new List<SystemTranslateDetailResultModel>();
            }

            var text = new TranslateRequest()
            {
                sysCode = "MES",
                srcLang = !string.IsNullOrEmpty(srcLang) ? srcLang.ToLower() : "zh",
                tgtLang = lang.ToLower(),
            };

            values.ForEach(o =>
            {
                text.text.Add(o);
            });

            WebApiPostRequest request = new WebApiPostRequest
            {
                Url = this.config["Translate"],
                Obj = text
            };

            var result = new List<SystemTranslateDetailResultModel>();
            try
            {
                var response = await WebApiUtils.PostAsync(request);
                //// ret.Result = response.Data;
                var translateReponse = response?.Data?.ToObjectFromJson<TranslateReponse>();

                var index = 0;
                foreach (var item in values)
                {
                    var val = translateReponse != null && translateReponse.data != null && translateReponse.data.text != null && translateReponse.data.text.Count > index ? translateReponse.data.text[index] : null;
                    if (string.IsNullOrEmpty(val))
                    {
                        index++;
                        continue;
                    }

                    result.Add(new SystemTranslateDetailResultModel
                    {
                        TranValue = val,
                        SrcValue = item,
                        Lang = lang,
                    });

                    index++;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return result;
        }

        private async Task<List<m_base_label>> LangChangeAsync(List<m_base_label> model)
        {
            var text = new TranslateRequest()
            {
                sysCode = "MES",
                srcLang = "auto",
                tgtLang = "en",
            };

            model.ForEach(o =>
            {
                text.text.Add(o.label_label_cn);
            });

            WebApiPostRequest request = new WebApiPostRequest
            {
                Url = this.config["Translate"],
                Obj = text
            };

            var response = await WebApiUtils.PostAsync(request);
            var translateReponse = response?.Data.ToObjectFromJson<TranslateReponse>();
            if (translateReponse == null || translateReponse.data == null || translateReponse.data.text == null)
            {
                return null;
            }

            var index = 0;
            foreach (var item in model)
            {
                if (string.IsNullOrEmpty(item.label_label_en))
                {
                    var tem = translateReponse.data.text[index];
                    if (item.label_label_cn != tem)
                    {
                        item.label_label_en = tem;
                    }
                }

                index++;
            }

            text.tgtLang = "th";
            request = new WebApiPostRequest
            {
                Url = this.config["Translate"],
                Obj = text
            };

            response = await WebApiUtils.PostAsync(request);
            translateReponse = response?.Data.ToObjectFromJson<TranslateReponse>();
            if (translateReponse == null)
            {
                return null;
            }

            index = 0;
            foreach (var item in model)
            {
                if (string.IsNullOrEmpty(item.label_label_th))
                {
                    var tem  = translateReponse.data.text[index];
                    if (item.label_label_cn != tem)
                    {
                        item.label_label_th = tem;
                    }
                }

                index++;
            }

            return model;
        }

        ////private async Task<List<t_base_label_detail>> LangChangeAsync(List<t_base_label_detail> model, string lang)
        ////{
        ////    var translateModel = model.Where(p => p.lang == "CN").ToList();
        ////    var text = new TranslateRequest()
        ////    {
        ////        sysCode = "MES",
        ////        srcLang = "zh",
        ////        tgtLang = lang,
        ////    };

        ////    translateModel.ForEach(o =>
        ////    {
        ////        text.text.Add(o.label);
        ////    });

        ////    WebApiPostRequest request = new WebApiPostRequest
        ////    {
        ////        Url = this.config["Translate"],
        ////        Obj = text
        ////    };

        ////    TranslateReponse translateReponse = null;
        ////    try
        ////    {
        ////        var response = await WebApiUtils.PostAsync(request);
        ////        translateReponse = response?.Data?.ToObjectFromJson<TranslateReponse>();
        ////    }
        ////    catch
        ////    {
        ////    }

        ////    if (translateReponse == null || translateReponse.data == null || translateReponse.data.text == null)
        ////    {
        ////        return null;
        ////    }

        ////    var result = new List<t_base_label_detail>();
        ////    var index = 0;
        ////    foreach (var item in translateModel)
        ////    {
        ////        result.Add(new t_base_label_detail
        ////        {
        ////            label = translateReponse.data.text[index],
        ////            base_label_id = item.base_label_id,
        ////            lang = lang == "en" ? "EN" : "TH",
        ////            org_id = item.org_id,
        ////        });

        ////        index++;
        ////    }

        ////    return result;
        ////}

        private LibMessageApiResultModel GetLibMessageApiResultModel(List<t_base_label> baseLabels, List<t_base_label_detail> baseLabelDetails)
        {
            LibMessageApiResultModel result = new LibMessageApiResultModel();
            ////var enbaseLabelDetails = await LangChangeAsync(baseLabelDetails, "en");
            ////var thbaseLabelDetails = await LangChangeAsync(baseLabelDetails, "th");
            ////if (enbaseLabelDetails != null)
            ////{
            ////    baseLabelDetails.AddRange(enbaseLabelDetails.Where(t => !baseLabelDetails.Any(t3 => t3.base_label_id == t.base_label_id && t3.lang == t.lang)));
            ////}

            ////if (thbaseLabelDetails != null)
            ////{
            ////    baseLabelDetails.AddRange(thbaseLabelDetails.Where(t => !baseLabelDetails.Any(t3 => t3.base_label_id == t.base_label_id && t3.lang == t.lang)));
            ////}

            baseLabels.GroupBy(t => t.label_key).ForEach(t2 =>
              {
                  var t = t2.FirstOrDefault();
                  var msg = new LibMessageApiMsgModel() { Code = t.label_key };
                  result.Messages.Add(msg);

                  baseLabelDetails.Where(t2 => t2.base_label_id == t.id).ForEach(t2 =>
                  {
                      msg.Details.Add(new LibMessageApiMsgDetailModel() { Format = t2.label, Lang = t2.lang });
                  });
              });

            return result;
        }

        private void DoAddLabelDetail(t_base_label baseLabel, List<t_base_label_detail> baseLabelDetails, List<t_base_label_detail> addBaseLabelDetails, List<t_base_label_detail> updateBaseLabelDetails, string label, string langg)
        {
            var detail = baseLabelDetails?.FirstOrDefault(t => t.base_label_id == baseLabel.id && t.lang == langg);
            if (detail == null)
            {
                if (string.IsNullOrEmpty(label))
                {
                    return;
                }

                detail = new t_base_label_detail() { base_label_id = baseLabel.id, lang = langg, org_id = baseLabel.org_id };
                this.SetEntityId(detail, detail.base_label_id);
                addBaseLabelDetails.Add(detail);
                baseLabelDetails.Add(detail);
            }
            else
            {
                if (detail.label == label)
                {
                    return;
                }

                detail.is_edit_by_menu = true;
                updateBaseLabelDetails.Add(detail);
            }

            detail.label = label;
        }

        private async Task FillLangDataByBaseLabelAsync(List<m_base_label> list)
        {
            if (list == null)
            {
                return;
            }

            var baseLabelIds = list.Select(t => t.id).ToList();
            var baseLabelDetails = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label_detail>(null, t => baseLabelIds.Contains(t.base_label_id));
            baseLabelDetails.ForEach(t =>
            {
                var le = list.FirstOrDefault(t2 => t2.id == t.base_label_id);
                if (le == null)
                {
                    return;
                }

                var l = string.IsNullOrEmpty(t.lang) ? lang : t.lang;
                if (l?.Trim().ToLower() == "cn")
                {
                    le.label_label_cn = t.label;
                }
                else if (l?.Trim().ToLower() == "en")
                {
                    le.label_label_en = t.label;
                }
                else if (l?.Trim().ToLower() == "th")
                {
                    le.label_label_th = t.label;
                }
            });
        }

        private async Task<(List<t_base_label>, List<t_base_label_detail>)> GetBaseLabelByCodeAsync(int type, string apiKey, List<string> codes)
        {
            List<t_base_label> bs = new List<t_base_label>();
            List<t_base_label_detail> ds = new List<t_base_label_detail>();

            if (codes.Count <= 200)
            {
                var baseLabels = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label>(null, t => t.type == 2 && t.api_key == apiKey && codes.Contains(t.label_key));
                var baseLabelIds = baseLabels.Select(t => t.id).ToList();
                var baseLabelDetails = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label_detail>(null, t => baseLabelIds.Contains(t.base_label_id));
                bs.AddRange(baseLabels);
                ds.AddRange(baseLabelDetails);
            }
            else
            {
                var temps = new List<string>();

                foreach (var v in codes)
                {
                    temps.Add(v);
                    if (temps.Count >= 200)
                    {
                        var baseLabels = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label>(null, t => t.type == 2 && t.api_key == apiKey && temps.Contains(t.label_key));
                        var baseLabelIds = baseLabels.Select(t => t.id).ToList();
                        var baseLabelDetails = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label_detail>(null, t => baseLabelIds.Contains(t.base_label_id));
                        bs.AddRange(baseLabels);
                        ds.AddRange(baseLabelDetails);

                        temps.Clear();
                    }
                }

                if (temps.Any())
                {
                    var baseLabels = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label>(null, t => t.type == 2 && t.api_key == apiKey && temps.Contains(t.label_key));
                    var baseLabelIds = baseLabels.Select(t => t.id).ToList();
                    var baseLabelDetails = await this.baseRepository.CommonRepository.GetEntitiesAsync<t_base_label_detail>(null, t => baseLabelIds.Contains(t.base_label_id));
                    bs.AddRange(baseLabels);
                    ds.AddRange(baseLabelDetails);
                }
            }

            return (bs, ds);
        }
    }
}
